package net.findbugs.demo.detect;

import org.apache.bcel.Constants;
import org.apache.bcel.classfile.Method;

import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.BugReporter;
import edu.umd.cs.findbugs.BytecodeScanningDetector;
import edu.umd.cs.findbugs.Priorities;

public class FindSystemGCInvocations extends BytecodeScanningDetector {
	private BugReporter bugReporter;
	private boolean inMain;
	private boolean inFinalizer;
	
	public FindSystemGCInvocations(BugReporter bugReporter) {
		this.bugReporter = bugReporter;
	}
	
	@Override
	public void visit(Method obj) {
		inMain = obj.getName().equals("main");
		inFinalizer = obj.getName().equals("finalize");
	}
	
	@Override
	public void sawOpcode(int seen) {
		if (seen != Constants.INVOKESTATIC) {
			return;
		}
		
		String calledClassName = getClassConstantOperand();
		String calledMethodName = getNameConstantOperand();
		String calledMethodSig = getSigConstantOperand();
		
		if (calledClassName.equals("java/lang/System")
				&& calledMethodName.equals("gc")
				&& calledMethodSig.equals("()V")) {
			emitWarning();
		}
	}

	private void emitWarning() {
		if (inMain) {
			return;
		}
		String type = inFinalizer ?
				"SGC_SYSTEM_GC_IN_FINALIZER" : "SGC_SYSTEM_GC";
		int priority = inFinalizer ?
				Priorities.HIGH_PRIORITY : Priorities.NORMAL_PRIORITY;
		BugInstance warning = new BugInstance(this, type, priority)
			.addClassAndMethod(this)
			.addSourceLine(this);
		bugReporter.reportBug(warning);
    }
}
